package hu.mapro.gwtui.gxt.client.fieldseditor;

import java.util.Arrays;
import java.util.List;
import java.util.Map;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.gwt.editor.client.EditorDelegate;
import com.google.gwt.editor.client.HasEditorDelegate;
import com.google.gwt.event.shared.HandlerRegistration;
import com.sencha.gxt.widget.core.client.container.VerticalLayoutContainer;
import com.sencha.gxt.widget.core.client.container.VerticalLayoutContainer.VerticalLayoutData;
import com.sencha.gxt.widget.core.client.form.FieldLabel;

public class FieldsEditorBuilder<T, F> implements Provider<T> {

	protected Interface<T, F> mainInterface;

	public FieldsEditorBuilder() {
		super();
	}
	
	List<EditorField<?>> fields = Lists.newArrayList();
	Map<F, EditorField<?>> fieldMap = Maps.newHashMap();
	
	public void add(F[] fields) {
		add(Arrays.asList(fields));
	}
	public void add(Iterable<F> fields) {
		for (F f : fields) {
			add(f);
		}
	}
	public <V> EditorField<V> add(F field) {
		@SuppressWarnings("unchecked")
		EditorField<V> f = (EditorField<V>) fieldMap.get(field);
		
		if (f==null) {
			f = new EditorField<V>(field);
			fields.add(f);
			fieldMap.put(field, f);
		}
		
		return f;
	}

	FieldsEditorComponent<T> editorComponent = null;

	
	@Override
	public FieldsEditorComponent<T> asFieldsEditorComponent(FieldCreationInterface ctx) {
		if (editorComponent==null) {
			createEditorComponent(ctx);
			//initializer.initialize(editorComponent);
		}
		return editorComponent;
	}
	
	
	protected void createEditorComponent(FieldCreationInterface ctx) {
		VerticalLayoutContainer vlc = new VerticalLayoutContainer();
		//vlc.setScrollMode(ScrollMode.AUTOY);
		VerticalLayoutData vld = new VerticalLayoutContainer.VerticalLayoutData(1, -1);
		
		for (EditorField<?> field : fields) {
			
			field.editorField.setContext(ctx);
			
			vlc.add(field.getFieldLabel(), vld);
			
		}
		
		editorComponent = new FieldsEditorComponent<T>(this, vlc);
	}


	public class EditorField<V> {
		
		F baseField;
		EditorFieldInterface<T, V> editorField;
		FieldLabel fieldLabel;
		
		public EditorField(F field) {
			this.baseField = field;

			editorField = mainInterface.createEditorField(field);
			//editorField.setContext(fieldCreationContext);
			
		}
		
		V getValue(T object) {
			return editorField.getValue(object);
		}
		
		class LeafEditor implements HasEditorDelegate<V> {

			public void edit(T value) {
				editorField.edit(value);
			}

			public String getPathElement() {
				return editorField.getPropertyName();
			}

			@Override
			public void setDelegate(final EditorDelegate<V> delegate) {
				editorField.setDelegate(new EditorDelegate<V>() {

					@Override
					public String getPath() {
						return delegate.getPath();
					}

					@Override
					public void recordError(String message, Object value,
							Object userData) {
						delegate.recordError(getFieldLabel().getText()+" "+message, value, userData);
					}

					@Override
					public void setDirty(boolean dirty) {
						delegate.setDirty(dirty);
					}

					@Override
					public HandlerRegistration subscribe() {
						return delegate.subscribe();
					}
				});
			}


		}
		
		public void flush() {
			editorField.flush();
		}
		
		LeafEditor leafEditor = new LeafEditor();

		public FieldLabel getFieldLabel() {
			if (fieldLabel==null) {
				fieldLabel = new FieldLabel(editorField.asWidget(), editorField.getLabel());
			}
			return fieldLabel;
		}
	}


	public void checkDirty() {
		for (EditorField<?> f : fields) {
			f.editorField.checkDirty();
		}
	}

	public void setMainInterface(Interface<T, F> mainInterface) {
		this.mainInterface = mainInterface;
	}

}
